%% 
%% Common functions for time measurement.
%% 
%%
%% ?SYSTEM, ?SYSTEM_SHORT, ?CLASSES, ?CATEGORIES
%%
-export([
    readtest/1,
    writetest/1,
    readtest2/1,
    writetest2/1,
    calltest/1,
    loop/3,
    dummy/1,
    
    %float_to_latex/1,
    
    test/3,
    %ioprint/1,
    
    alltex/0,
    alltest_raw/0,
    alltest_raw_to_file/0,
    alltest_format/1
    
    ]).

-define(MEASUREMENTS, 10).
-define(DROP, 2).

-define(OPS_BASE,100000).  % 100000
%-define(OPS_BASE,100).
-define(OPS,?OPS100k*?OPS_BASE).

-include("../measure_defs.hrl").

type_to_name(readtest2) ->
    "Read time V2 (us) ";
type_to_name(writetest2) ->
    "Write time V2 (us) ";
type_to_name(readtest) ->
    "Read time (us) ";
type_to_name(writetest) ->
    "Write time (us) ";
type_to_name(calltest) ->
    "Call time (us) ".


dummy(_) ->
    ok.

loop(0, _, _) ->
    ok;
loop(N, Obj, Fun) ->
    ?MODULE:Fun(Obj),
    loop(N-1, Obj, Fun).

doall(0, _, _) ->
    [];
doall(N, Fun, ClassName) ->
    L = doall(N-1, Fun, ClassName),
    Obj = init_object(ClassName),
    {Res1, ok} = timer:tc(?MODULE, loop, [?OPS, Obj, Fun]),
    {Res2, ok} = timer:tc(?MODULE, loop, [10*?OPS, Obj, dummy]),
    dispose_object(Obj),
    [Res1-Res2/10|L].

test(Fun, ClassName, Name) ->
    io:format("testing fun=~p class=~p... ", [Fun, ClassName]),
    L1 = doall(?MEASUREMENTS+?DROP, Fun, ClassName),
    L3 = lists:sublist(L1, 1, ?MEASUREMENTS),   % last two in the list were the measured first two
    ?MEASUREMENTS = length(L3),
    %L2 = lists:sort(L3),
%     L3 = L1, %lists:sublist(L2, ?DROP+1, ?MEASUREMENTS-2*?DROP),
    Sum = lists:sum(L3),
    Avg = Sum / length(L3),
    Ops = ?OPS,
    OpAvg = Avg / Ops,
    %Var = abs(lists:last(L3) - hd(L3)) / Avg * 100,
    
    io:format("done~n", []),
    #results{ops = Ops, avg = OpAvg, ms = L3, name = Name, classname = ClassName}.

allclasses([], _) ->
    [];
allclasses([Class|Classes], TestType = {special, Prefix, BaseType}) ->
    [test(list_to_atom(Prefix++atom_to_list(Class)), Class, type_to_name(BaseType))
    |allclasses(Classes, TestType)
    ];
allclasses([Class|Classes], TestType) ->
    [test(TestType, Class, type_to_name(TestType))
    |allclasses(Classes, TestType)
    ].

allcategories([]) ->
    [];
allcategories([{TestType, Classes}|Cats]) ->
    [allclasses(Classes, TestType)
    |allcategories(Cats)
    ];
allcategories([TestType|Cats]) ->
    [allclasses(?CLASSES, TestType)
    |allcategories(Cats)
    ].



%%
%% PRESENTATION
%%

% ioprint(#results{ops = Ops, avg = OpAvg, var = Var, classname = ClassName, name = Name, ms = Ms, avs = Avs}) ->
%     io:format(Name++" (~p)~n", [ClassName]),
%     io:format("Measured   = ~p~n", [Ms]),
%     io:format("Averaged   = ~p~n", [Avs]),
%     io:format("variance   = ~p %~n", [Var]),
%     io:format("nr of ops  = ~p ~n", [Ops]),
%     io:format("op average = ~p us~n", [OpAvg]).


alltest_raw() ->
    #all_results{
        res_list = allcategories(?CATEGORIES),
        sys_name = ?SYSTEM,
        sys_short_name = ?SYSTEM_SHORT
    }.

alltest_format(Fs) ->
    T = alltest_raw(),
    lists:map(fun (Fo) -> Fo:format(T) end, Fs).

alltex() ->
    alltest_format([output_latex_sum, output_latex_full]).

alltest_raw_to_file() ->
    T  = alltest_raw(),
    B = io_lib:print(T)++".\n",
    file:write_file("../results/"++?SYSTEM_SHORT++".dat", B).